#include "transContentFuncCallTracertTarget.hpp"

///////////////////////////////////////////////////////////////
/// tracert the nodes to target
///		use data fifo send data to stack
///
///		name | length | mainCode | subCode | localPort | target | tracertflag |
///		len  |    2   |    1     |    1    |    4      |   8    |     1       |
///   offset |    0   |    2     |    3    |    4      |   8    |     16      |
///
/// parameters:
///		nodeList: the node array
///		nodeCount: the node array size
///
///	return:
///		count: the fixed node count;
///		E_TRANC_TIMEOUT: operation timeout
///		E_TRANC_NONBLOCK: the operation use sync style
///		E_TRANC_BufferTooSmall: buffer too small
///		E_TRANC_ParamError: the max supply fields not set
///////////////////////////////////////////////////////////////
int tracertTarget(NodeAddr* nodeList, int nodeCount){
	char buffer[24] = {0};
	int result = 0;
	debug_enter();

	if(localPort <= 0 || target.serial_id <= 0 || nodeList == NULL){
		logd_error("tracertTarget check filed failed!");
		return E_TRANC_ParamError;
	}
	timespec = TransContentAssis::TimeTp2Ts(timeout);
	logd_info("construct the packet");
	*(short*(buffer)) = (short)17;
	buffer[2] = (char)message_type_inner_functionCall_tracertTarget_request;
	*(int*(buffer+4)) = localPort;
	*(NodeAddr*(buffer+8)) = target;
	buffer[16] = (char)tracertFlag;

	logd_info("start send to stack, use data fifo");
	TransContentDispatcher::getInstance()->sendDataDataToStack(buffer, 17);

	logd_info("send tracert request to stack finished, begin to wait or return nonblock");
	if(callback != NULL){
		logd_info("tracert target use no block style!!");
		return E_TRANC_NONBLOCK;
	}

	logd_info("tracert use block style!");
	pthread_mutex_lock(&waitMutex);
	if(pthread_cond_timedwait(&finishedCondtion, &waitMutex, &ts) == ETIMEDOUT){
		logd_error("wait tracert back timed out, the caller begin to return");
		goto End;
		result =  E_TRANC_TIMEOUT;
	}
	pthread_mutex_unlock(&waitMutex);
	if(nodeCount < pathNodeCount){
		logd_error("parameter node count less than the get value");
		result = E_TRANC_BufferTooSmall;
		goto End;
	}
	log_info("copy tracert result to parameter buffer");
	memcpy(nodeList, pathNodes, sizeof(NodeAddr)*pathNodeCount);
	result = pathNodeCount;
End:
	canBeRemoved = 1;
	return result;
}

///////////////////////////////////////////////////////////////////////////////
/// tracert target response
///		the packet contains the node value, extract them and alloc memory to store them
///
/// response content format
///		name | mainCode | subCode | localPort | target | result | pathCount | paths |
///   length |    1     |    1    |     4     |    4   |    1   |     1     |   xxx |
///    offset|    0     |    1    |     2     |    6   |    10  |     11    |   12  |
///
/// parameters:
///		content: response buffer
///		index: the buffer index in the memory pool
///
/// return:
///		RESPONSE_RESULT_DELETE_RECORD: delete the record after the method finished
///////////////////////////////////////////////////////////////////////////////
int tracertTargetResponse(char* content, int index){
	pthread_t pid;
	debug_enter();
	result = content[10];
	if(result == 1){
		pathNodeCount = content[11];
		pathNodes = (NodeAddr*)calloc(pathNodeCount+1, sizeof(NodeAddr));
		if(pathNodeAddr == NULL){
			logd_fata_error("calloc memory for path node failed!!: %s", strerror(errno));
			goto End;
		}
		//copy content
		memcpy(pathNodes, content+12, pathNodeCount*sizeof(NodeAddr));
	}
	/// start relase the buffer
	logd_info("release the response buffer");
	TransContentMemory::getInstance()->releaseBuffer(index);
	// if sync style
	if(callback != NULL){
		logd_info("response use sync style");
		pthread_create(&pid, NULL, finishedRoute, this);
		pthread_detach(pid);
	}else{
		logd_info("response use block style");
		pthread_mutex_lock(&waitMutex);
		pthread_cond_signal(&finishedCondtion);
		pthread_mutex_unlock(&waitMutex);
	}
	sleep(SYNC_METHOD_RETURN_TIME);
End:
	logd_info("response finished, begin to return");
	return RESPONSE_RESULT_DELETE_RECORD;
}
